import 'dart:async';

import 'package:dio/dio.dart';
import 'package:flutter_enjoy_plus/constants/index.dart';
import 'package:flutter_enjoy_plus/utils/EventBus.dart';
import 'package:flutter_enjoy_plus/utils/Toast.dart';
import 'package:flutter_enjoy_plus/utils/TokenManager.dart';

class RequestDio {
  //创建dio实例
  Dio dio = Dio();
  RequestDio() {
    dio.options.baseUrl = GlobalVariable.BASE_URL;
    dio.options.connectTimeout =
        const Duration(seconds: GlobalVariable.Timeout);
    dio.options.receiveTimeout =
        const Duration(seconds: GlobalVariable.Timeout);
    _registerInterceptors();
  }
  //封装get请求方法
  Future get(String url, {Map<String, dynamic>? params}) async {
    final result = await dio.get(url, queryParameters: params);
    return _handleResult(result);
  }

  //封装post请求方法
  Future post(String url, {Map<String, dynamic>? data}) async {
    final result = await dio.post(url, data: data);
    return _handleResult(result);
  }

  //封装图片上传方法
  Future upload(String url, {FormData? data}) async {
    final result = await dio.post(url, data: data);
    return _handleResult(result);
  }

  //封装put请求方法
  Future put(String url, {Map<String, dynamic>? data}) async {
    final result = await dio.put(url, data: data);
    return _handleResult(result);
  }

  //封装delete请求方法
  Future delete(String url, {Map<String, dynamic>? data}) async {
    final result = await dio.delete(url, data: data);
    return _handleResult(result);
  }

  //针对所有请求封装处理返回结果函数
  _handleResult(Response<dynamic> response) {
    if (response.data["code"] == 10000) {
      return response.data["data"];
    }
    //请求业务失败 -> 抛出异常给程序员看 提示用户给用户看
    //提示用户
    PromptAction.showErrorToast(response.statusMessage as String);
    throw Exception(response.data["message"]);
  }

  // 判断refreshToken是否过期
  Future<bool> _isRefreshTokenExpired() async {
    // 1. 获取刷新token
    // 2. 发请求 -> /refreshToken
    // 3. 该请求中传入refreshToken
    // 4. 根据状态码 来判断token是否过期
    final refreshToken = tokenManager.getRefreshToken();
    // 注意点: 自己创建一个dio实例 -> 为了避免使用之前的dio实例发请求 (携带的token -> 过期的)
    Dio dio = Dio();
    try {
      final res = await dio.post(
          '${GlobalVariable.BASE_URL}${HTTP_PATH.REFRESH_TOKEN}',
          options: Options(headers: {'Authorization': 'Bearer $refreshToken'}));
      if (res.data['code'] == 10000) {
        // 刷新token成功了
        // 将获取到的最新的token和refreshToken 进行存储
        tokenManager.setToken(res.data['data']['token'],
            refreshToken: res.data['data']['refreshToken']);
        return true;
      } else {
        return false;
      }
    } catch (e) {
      return false;
    }
  }

  _registerInterceptors() {
    dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
          // 如果你想完成请求并返回一些自定义数据，你可以使用 `handler.resolve(response)`。
          // 如果你想终止请求并触发一个错误，你可以使用 `handler.reject(error)`。
          //请求头携带token
          final token = tokenManager.getToken();
          if (token.isNotEmpty) {
            options.headers["Authorization"] = "Bearer $token";
          }
          return handler.next(options);
        },
        onResponse: (Response response, ResponseInterceptorHandler handler) {
          // 如果你想终止请求并触发一个错误，你可以使用 `handler.reject(error)`。
          if (response.statusCode! >= 200 && response.statusCode! <= 300) {
            return handler.next(response);
          } else {
            //4开头 （客户端异常） 5开头（服务器异常）
            //针对401单独处理
            //提示用户
            PromptAction.showErrorToast(response.statusMessage as String);
            //返回一个错误的Future 鸿蒙和前端中事返回一个错误的promise
            return handler.reject(DioException(
              requestOptions: response.requestOptions,
              error: response.statusMessage,
              type: DioExceptionType.badResponse,
            ));
          }
        },
        onError: (DioException error, ErrorInterceptorHandler handler) async {
          // 如果你想完成请求并返回一些自定义数据，你可以使用 `handler.resolve(response)`。
          if (error.response?.statusCode == 401) {
            // tokenManager.removeToken();
            // eventBus.fire(LogoutEvent());
            final refreshToken = tokenManager.getRefreshToken();
            if (refreshToken.isNotEmpty) {
              // 刷新token存在的情况 ??????
              // 是否过期 封装方法 -> 返回布尔值 true -> 没有过期 / 返回false 过期
              bool isOK = await _isRefreshTokenExpired();
              if (isOK) {
                //  刷新token没有过期 -> 存储最新的token和refreshToken -> 发送请求更新我的页面的视图
                //重新拉起之前失败的请求
                final res = await dio.fetch(error.requestOptions);
                // 如果你想完成请求并返回一些自定义数据，你可以使用 `handler.resolve(response)`。
                return handler.resolve(res);
              } else {
                // 刷新token过期
                // 清除本地缓存
                // 跳转到登录页
                tokenManager.removeToken();
                eventBus.fire(LogoutEvent());
              }
            } else {
              // 刷新token不存在的情况
              // 清除本地缓存
              // 跳转到登录页
              tokenManager.removeToken();
              eventBus.fire(LogoutEvent());
            }
          }
          return handler.next(error);
        },
      ),
    );
  }
}

RequestDio requestDio = RequestDio();
